use std::collections::HashMap;
use std::fs::{File, OpenOptions};
use std::io::Write;
use std::path::Path;
use std::process::exit;

use reqwest::blocking::Client;
use reqwest::header::HeaderMap;
use serde::{Deserialize};
use uuid::Uuid;

#[derive(Deserialize, Debug)]
struct Msg {
    name: String,
    // 某些同学电话号可能是无
    phone: Option<String>,
}

#[derive(Deserialize, Debug)]
struct Page {
    list: Vec<Msg>,
}

#[derive(Deserialize, Debug)]
struct Data {
    page: Page,
}

#[derive(Deserialize, Debug)]
struct Token {
    token: Option<String>,
}

fn get_student_data(client: &Client, token: &String, count: u8, page: u16) {
    // 添加header信息
    let mut headers = HeaderMap::new();
    headers.insert("token", token.as_str().parse().unwrap());

    // 请求地址
    let url = format!("http://211.67.143.11:9010/yunT/yt/ytstudentinfo/list?page={}&limit={}", page, count);

    // 发送请求
    let resp = &client.get(url)
        .headers(headers)
        .send().unwrap()
        .json::<Data>().unwrap();

    // 预创建空间
    let mut list = Vec::with_capacity(100);

    // 拼接数据
    for data in &resp.page.list {
        // 处理电话号码可能是None的情况
        let str = match &data.phone {
            Some(tel) => format!("{}\t{}", data.name, tel),
            None => format!("{}\t无", data.name)
        };

        list.push(str);
    }

    // 存在数据，进行追加
    if Path::new("data.txt").exists() {
        let mut file = OpenOptions::new().append(true).open("data.txt").unwrap();
        file.write_all(list.join("\n").as_ref());
    }
    // 数据不存在，创建并写入
    else {
        let mut file = File::create("data.txt").unwrap();
        file.write_all(list.join("\n").as_ref());
    }
}

fn get_login(client: &Client, code: String, uuid: &String) -> String {
    // 添加参数
    let header = {
        let mut header = HashMap::new();

        header.insert("captcha", code.to_string());
        header.insert("password", "xxxxxxxxxxx".to_string()); // 在此输入账号
        header.insert("username", "xxxxxxxxxxx".to_string()); // 在此输入密码
        header.insert("uuid", uuid.to_string());
        header
    };

    // 发送登录请求
    let resp = &client.post("http://211.67.143.11:9010/yunT/app/login")
        .json(&header)
        .send().unwrap()
        .json::<Token>().unwrap();

    match &resp.token {
        Some(token) => token.to_string(),
        None => {
            println!("没获取到token");
            exit(1)
        }
    }
}

fn accept_user_input() -> String {
    println!("请输入验证码");

    let mut s = String::new();
    std::io::stdin().read_line(&mut s).expect("");

    s.trim().to_string()
}

fn get_code_pic(code: &String, client: &Client) {
    let url = format!("http://211.67.143.11:9010/yunT/captcha.jpg?uuid={}", code);

    // 发送请求
    let resp = &client.get(url).send().unwrap().bytes().unwrap();

    // 将图片保存到本地
    let mut file = File::create("1.jpg").unwrap();
    file.write_all(resp).unwrap();
}

fn main() {
    // 定义uuid4
    let uuid: String = Uuid::new_v4().to_string();

    // 定义客户端连接
    let client = reqwest::blocking::Client::new();

    // 下载图片
    get_code_pic(&uuid, &client);

    // 接受用户输入
    let code = accept_user_input();

    // 登录获得token
    let token = get_login(&client, code, &uuid);

    // 定义要抓取的页数以及每页显示多少条，每页显示不能超过100条
    // 获取学生数据并写入文件
    for page in 0..2 {
        get_student_data(&client, &token, 100, page);
    }
}